#include "remote/server/server.h"

namespace remote {

RemoteServer::RemoteServer(boost::asio::io_service &io_service)
  : io_service_(io_service) {
}

RemoteServer::~RemoteServer() {

}
// default addr 127.0.0.1
// default port 5299
bool RemoteServer::StartRemoteServer(RemoteServerSettings &settings) {
  if (tcp_server_) {
    LOG(ERROR) << "Can't reinit the connect server";
    return false;
  }
  try {
    LOG(INFO) << "Start create local tcp server "
              << settings.control_addr_
              << ":" << settings.control_port_;
    tcp_server_ = vzconn::VzServer::CreateTcpServer(
                    io_service_,
                    settings.control_addr_,
                    settings.control_port_);
    if (!tcp_server_) {
      LOG(ERROR) << "Failure to create tcp server";
      return false;
    }
    tcp_server_->SignalNewConnect.connect(
      boost::bind(&RemoteServer::OnNewControlConnect,
                  shared_from_this(), _1, _2));
    tcp_server_->SignalVzServerError.connect(
      boost::bind(&RemoteServer::OnControlServerError,
                  shared_from_this(), _1, _2));
    return tcp_server_->Start();
    LOG(INFO) << "Create Local tcp server succeed";
  } catch (std::exception &e) {
    LOG(ERROR) << e.what();
    return false;
  }
  return true;
}

void RemoteServer::StopRemoteServer() {

}


void RemoteServer::OnNewControlConnect(vzconn::VzServer::Ptr tcp_server,
                                       vzconn::VzConnect::Ptr tcp_connect) {
  ControlSession::Ptr session(new ControlSession(io_service_, tcp_connect));
  session->SignalRegisterEvent.connect(
    boost::bind(&RemoteServer::OnSessionRegister,
                shared_from_this(), _1, _2));
  session->StartSession();
}

void RemoteServer::OnControlServerError(vzconn::VzServer::Ptr tcp_server,
                                        const boost::system::error_code& err) {
}

void RemoteServer::OnSessionRegister(ControlSession::Ptr control_session,
                                     bool *res) {
  ControlSessions::iterator iter = control_sessions_.find(
                                     control_session->session_name());
  if(iter != control_sessions_.end()) {
    LOG(ERROR) << "The session has it own name";
    *res = false;
    return;
  }
  control_sessions_.insert(std::pair<std::string, ControlSession::Ptr>(
                             control_session->session_name(),
                             control_session));
  control_session->SignalCloseEvent.connect(
    boost::bind(&RemoteServer::OnSessionClose, shared_from_this(), _1));
  control_session->SignalSessionEvent.connect(
    boost::bind(&RemoteServer::OnSessionEvent, shared_from_this(), _1, _2));
  *res = true;
}

void RemoteServer::OnSessionClose(ControlSession::Ptr control_session) {
  ControlSessions::iterator iter = control_sessions_.find(
                                     control_session->session_name());
  if(iter == control_sessions_.end()) {
    LOG(WARNING) << "The session not found";
    return;
  }
  control_sessions_.erase(iter);
}

void RemoteServer::OnSessionEvent(ControlSession::Ptr control_session,
                                  QueryStanza::Ptr stanza) {
  if(stanza->to() == DEFAULT_SERVER_NAME) {
    ProcessServerEvent(control_session, stanza);
    return;
  }
  ControlSessions::iterator iter = control_sessions_.find(
                                     stanza->to());
  if(iter == control_sessions_.end()) {
    QueryStanza::Ptr response = QueryStanza::CreateQueryStanza(
                                  stanza->type(),
                                  stanza->state(),
                                  stanza->id(),
                                  stanza->to(),
                                  stanza->from());
    control_session->AsyncWrite(response);
  } else {
    iter->second->AsyncWrite(stanza);
  }
}

void RemoteServer::ProcessServerEvent(ControlSession::Ptr control_session,
                                      QueryStanza::Ptr stanza) {
  if(stanza->type() == JSON_TYPE_SERVER_GET_ONLINE_SESSION) {
    ProcessGetOnlineSession(control_session, stanza);
  }
}

void RemoteServer::ProcessGetOnlineSession(
  ControlSession::Ptr control_session,
  QueryStanza::Ptr stanza) {
  Json::Value online_sessions(Json::arrayValue);
  online_sessions.append("adfasdfasdfasfs@server.com");
  online_sessions.append("adfasdfasdffs@server.com");
  online_sessions.append("aasdfasdfafs@server.com");
  online_sessions.append("adadfsdfadfs@server.com");
  online_sessions.append("adasasadsfs@server.com");
  for(ControlSessions::iterator iter = control_sessions_.begin();
      iter != control_sessions_.end(); ++iter) {
    online_sessions.append(iter->second->session_name());
  }
  QueryStanza::Ptr response = QueryStanza::CreateQueryStanza(
                                stanza->type(),
                                STATE_SERVER_SUCCEED,
                                stanza->id(),
                                stanza->from(),
                                stanza->to());
  response->set_body(online_sessions);
  control_session->AsyncWrite(response);
}
}